//////////////////////////////////////////////
// Vector.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Forward decl -----------------------------

namespace nkMaths
{
	class IntVector ;
	class Matrix ;
	class Quaternion ;
}

/// Includes ---------------------------------

// nkGraphics
#include "../Dll/DllDefines.h"

// nkCommon
#include <nilkinsCommon/Patterns/ByteAlignedClass.h>

// nkMemory
#include <NilkinsMemory/Containers/String.h>
#include <NilkinsMemory/Containers/StringView.h>

/// Class ------------------------------------

namespace nkMaths
{
	class DLL_MATHS_EXPORT Vector
	{
		public :
		
			// Constructor, destructor
			Vector () noexcept ;
			Vector (float x, float y) noexcept ;
			Vector (float x, float y, float z) noexcept ;
			Vector (float x, float y, float z, float w) noexcept ;
			Vector (const Vector& other) noexcept ;
			Vector (const IntVector& other) noexcept ;

			// Length
			float getLengthVec2 () const ;
			float getLengthVec3 () const ;
			float getLengthVec4 () const ;
			float getLengthSquaredVec2 () const ;
			float getLengthSquaredVec3 () const ;
			float getLengthSquaredVec4 () const ;
			// Distance
			float getDistanceVec2 (const Vector& other) const ;
			float getDistanceVec3 (const Vector& other) const ;
			float getDistanceVec4 (const Vector& other) const ;
			float getDistanceSquaredVec2 (const Vector& other) const ;
			float getDistanceSquaredVec3 (const Vector& other) const ;
			float getDistanceSquaredVec4 (const Vector& other) const ;
			// Normalization
			Vector& normalizeVec2 () ;
			Vector& normalizeVec3 () ;
			Vector& normalizeVec4 () ;
			Vector getNormalizedVec2 () const ;
			Vector getNormalizedVec3 () const ;
			Vector getNormalizedVec4 () const ;
			// Dot product
			float dotProductVec2 (const Vector& other) const ;
			float dotProductVec3 (const Vector& other) const ;
			float dotProductVec4 (const Vector& other) const ;
			// Cross product
			Vector& setAsCrossVec3 (const Vector& other) ;
			Vector getCrossVec3 (const Vector& other) const ;

			// Practical
			nkMemory::String toString () const ;
			Vector& fromString (nkMemory::StringView str) ;

			// Operators
			// Assignment
			Vector& operator= (const Vector& other) noexcept ;
			Vector& operator= (const IntVector& other) noexcept ;
			// Add
			Vector operator+ (const Vector& other) const ;
			void operator+= (const Vector& other) ;
			// Soustraction
			Vector operator- () const ;
			Vector operator- (const Vector& other) const ;
			void operator-= (const Vector& other) ;
			// Multiplication
			Vector operator* (const Vector& other) const ;
			void operator*= (const Vector& other) ;
			Vector operator* (const Quaternion& other) const ;
			void operator*= (const Quaternion& other) ;
			Vector operator* (const Matrix& mat) const ;
			void operator*= (const Matrix& other) ;
			Vector operator* (float coeff) const ;
			void operator*= (float coeff) ;
			// Division
			Vector operator/ (const Vector& other) const ;
			void operator/= (const Vector& other) ;
			Vector operator/ (float coeff) const ;
			void operator/= (float coeff) ;
			// Comparaison
			bool operator== (const Vector& other) const ;
			bool operator!= (const Vector& other) const ;
			bool operator< (const Vector& other) const ;
			bool operator<= (const Vector& other) const ;
			bool operator> (const Vector& other) const ;
			bool operator>= (const Vector& other) const ;

			// Statics
			// Distance
			static float distanceVec2 (const Vector& a, const Vector& b) ;
			static float distanceVec3 (const Vector& a, const Vector& b) ;
			static float distanceVec4 (const Vector& a, const Vector& b) ;
			static float distanceSquaredVec2 (const Vector& a, const Vector& b) ;
			static float distanceSquaredVec3 (const Vector& a, const Vector& b) ;
			static float distanceSquaredVec4 (const Vector& a, const Vector& b) ;
			// Dot product
			static float dotVec2 (const Vector& a, const Vector& b) ;
			static float dotVec3 (const Vector& a, const Vector& b) ;
			static float dotVec4 (const Vector& a, const Vector& b) ;
			// Cross product
			static Vector crossVec3 (const Vector& a, const Vector& b) ;

		public :

			// Attributes
			float _x ;
			float _y ;
			float _z ;
			float _w ;
	} ;

	// Alias to align with the IntVector if need be
	using FloatVector = Vector ;
}